package br.ufc.ck0017.frame.x86;

import br.ufc.ck0017.frame.Access;
import br.ufc.ck0017.frame.Frame;
import br.ufc.ck0017.ir.tree.IR;
import br.ufc.ck0017.ir.tree.IRNode;
import br.ufc.ck0017.temp.Color;
import br.ufc.ck0017.temp.Label;
import br.ufc.ck0017.temp.Temp;

import java.util.ArrayList;
import java.util.List;

public class X86Frame extends Frame {
    private int localCount;

    public static final int INITIAL_OFFSET = 8;
    public static final int WORD_SIZE = 4;

    private static final Temp FP = new Temp(new Color("ebp", true));
    private static final Temp RV = new Temp(new Color("eax", true));

    protected X86Frame(Label label, List<Access> formals) {
        super(label, formals);
    }

    @Override
    public Temp getFramePointer() {
        return FP;
    }

    @Override
    public Temp getReturnValuePointer() {
        return RV;
    }

    @Override
    public IRNode onMethodExit(IRNode body) {
        return IR.SEQ(IR.LABEL(super.label), body);
    }

    @Override
    public Integer getWordSize() {
        return WORD_SIZE;
    }

    @Override
    public Access allocateLocal(Boolean escape) {
        if (escape) {
            return new X86InFrame(-(WORD_SIZE * localCount++));
        }
        return new X86InRegister(new Temp());
    }

    @Override
    public Frame newFrame(Label name, List<Boolean> escapes) {
        int offset = INITIAL_OFFSET;
        List<Access> newFormals = new ArrayList<>();

        for (Boolean escape : escapes) {
            if (escape) {
                newFormals.add(new X86InFrame(offset));
                offset += WORD_SIZE;
            } else {
                newFormals.add(new X86InRegister(new Temp()));
            }
        }

        return new X86Frame(name, newFormals);
    }
}
